package com.unittec.zk.provider.auth.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.unittec.zk.provider.auth.entity.*;
import com.unittec.zk.provider.auth.util.SysPermissionComparator;
import com.unittec.zk.provider.auth.dto.SysPermissionTree;
import com.unittec.zk.provider.auth.dto.UserInfo;
import com.unittec.zk.provider.auth.mapper.SysPermissionMapper;
import com.unittec.zk.provider.auth.mapper.SysUserDepartMapper;
import com.unittec.zk.provider.auth.mapper.SysUserMapper;
import com.unittec.zk.provider.auth.mapper.SysUserRoleMapper;
import com.unittec.zk.provider.log.Log;
import com.unittec.zk.provider.root.ServiceRoot;
import com.unittec.zk.provider.utils.CopyListUtils;
import com.unittec.zk.provider.utils.DateUtils;
import com.unittec.zk.provider.utils.StringUtil;
import com.unittec.zk.sdk.auth.domain.SysUserInfo;
import com.unittec.zk.sdk.auth.domain.SysUserRes;
import com.unittec.zk.sdk.auth.request.Req101101;
import com.unittec.zk.sdk.auth.request.Req101121;
import com.unittec.zk.sdk.root.common.CommonConstant;
import com.unittec.zk.sdk.root.internal.exception.BusinessException;
import org.apache.commons.lang.StringUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Jason
 * @description 用户Service
 * @date 2019/11/07
 */
@Service
public class SysUserService extends ServiceRoot<SysUserMapper, SysUser> {

    @Resource
    private SysUserRoleMapper sysUserRoleMapper;

    @Resource
    private SysUserDepartMapper sysUserDepartMapper;

    @Resource
    private SysPermissionMapper sysPermissionMapper;

    @Resource
    Log log;

    @Resource
    private SysDepartService sysDepartService;

    /**
     * 根据用户名获取用户信息
     *
     * @param username
     * @return
     */
    public SysUser findUserByUsername(String username) {

        return getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
    }

    /**
     * 根据手机号获取用户信息
     *
     * @param phone
     * @return
     */
    public SysUser findUserByPhone(String phone) {

        return getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhone, phone));
    }

    /**
     * 根据id获取用户信息
     *
     * @return
     */
    public UserInfo getUserInfoById(String id) {

        return getMapper().getUserInfoById(id);
    }

    /**
     * 根据手机号获取用户信息
     *
     * @param phone
     * @return
     */
    public UserInfo getUserInfoByPhone(String phone) {

        return getMapper().getUserInfoByPhone(phone);
    }

    /**
     * 根据用户名获取用户信息
     *
     * @param username
     * @return
     */
    public UserInfo getUserInfoByUsername(String username) {

        return getMapper().getUserInfoByUsername(username);
    }

    /**
     * 查询所有用户列表
     *
     * @return
     */
    public List<Map<String, Object>> selectAllUserList(Map<String, Object> param) {

        return getMapper().selectAllUserList(param);
    }

    /**
     * 根据条件查询用户分页列表
     *
     * @param req101101
     * @return
     */
    public Page<Map<String, Object>> selectSysUserPage(Req101101 req101101) {
        LambdaQueryWrapper<SysUser> qw = new LambdaQueryWrapper<>();
        if (StringUtils.isNotEmpty(req101101.getUsername())) {
            qw.like(SysUser::getUsername, req101101.getUsername());
        }
        if (StringUtils.isNotEmpty(req101101.getRealname())) {
            qw.like(SysUser::getRealname, req101101.getRealname());
        }
        if (StringUtils.isNotEmpty(req101101.getPhone())) {
            qw.like(SysUser::getPhone, req101101.getPhone());
        }
        if (StringUtils.isNotEmpty(req101101.getStatus())) {
            qw.eq(SysUser::getStatus, req101101.getStatus());
        }
        if (StringUtils.isNotEmpty(req101101.getEmail())) {
            qw.eq(SysUser::getEmail, req101101.getEmail());
        }
        if (StringUtils.isNotEmpty(req101101.getSex())) {
            qw.eq(SysUser::getSex, req101101.getSex());
        }
        if (StringUtils.isNotEmpty(req101101.getType())) {
            qw.apply("FIND_IN_SET( {0}, type )", req101101.getType());
        }
        if (StringUtils.isNotEmpty(req101101.getPlatformCode())) {
            qw.apply("FIND_IN_SET( {0}, platform_code )", req101101.getPlatformCode());
        }
        if (req101101.getStartTime() != null && req101101.getEndTime() != null) {
            qw.apply("DATE_FORMAT(create_time,'%Y-%m-%d') >= {0}", DateUtils.parseDateToDateStr(req101101.getStartTime()));
            qw.apply("DATE_FORMAT(create_time,'%Y-%m-%d') <= {0}", DateUtils.parseDateToDateStr(req101101.getEndTime()));
        }
        if (req101101.getDeptIds() != null && req101101.getDeptIds().size() > 0) {
            LambdaQueryWrapper<SysUserDepart> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            if (req101101.getRecursionDeptStatus() != null && req101101.getRecursionDeptStatus()) {
                LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<>();
                query.eq(SysDepart::getDelFlag, CommonConstant.DELETE_NO);
                query.orderByAsc(SysDepart::getDepartOrder);
                List<SysDepart> allDeptList = sysDepartService.list(query);
                List<String> allSubDeptList = new ArrayList<>();
                for (String deptId : req101101.getDeptIds()) {
                    List<String> subDeptIds = new ArrayList<>();
                    recursionSubDeptIdsBySelf(allDeptList, deptId, subDeptIds);
                    allSubDeptList.addAll(subDeptIds);
                }
                lambdaQueryWrapper.in(SysUserDepart::getDepId, allSubDeptList);
            } else {
                lambdaQueryWrapper.in(SysUserDepart::getDepId, req101101.getDeptIds());
            }

            List<SysUserDepart> departUserList = sysUserDepartMapper.selectList(lambdaQueryWrapper);
            if (departUserList == null || departUserList.size() == 0) {
                qw.isNull(SysUser::getId);
            } else {
                List<String> userIds = new ArrayList<>();
                for (SysUserDepart sysUserDepart : departUserList) {
                    userIds.add(sysUserDepart.getUserId());
                }
                if (userIds.size() > 0) {
                    qw.in(SysUser::getId, userIds);
                }
            }
        }

        qw.eq(SysUser::getDelFlag, CommonConstant.DELETE_NO);
        qw.orderByDesc(SysUser::getCreateTime, SysUser::getId);
        Page<Map<String, Object>> page = getMapper().selectSysUserPage(new Page<>(req101101.getCurrent(), req101101.getSize()), qw);

        if (page.getRecords() != null && page.getRecords().size() > 0) {
            List<String> userIds = new ArrayList<>();
            for (Map<String, Object> map : page.getRecords()) {
                String id = map.get("id") == null ? "" : String.valueOf(map.get("id"));
                if (StringUtils.isNotBlank(id)) {
                    userIds.add(id);
                }
            }
            if (userIds.size() > 0) {
                List<Map<String, Object>> deptList = sysDepartService.getBaseMapper().getDeptInfoByUserIds(userIds);
                for (Map<String, Object> map : page.getRecords()) {
                    String id = map.get("id") == null ? "" : String.valueOf(map.get("id"));
                    for (Map<String, Object> userMap : deptList) {
                        String user_id = userMap.get("user_id") == null ? "" : String.valueOf(userMap.get("user_id"));
                        if(id.equalsIgnoreCase(user_id)){
                            map.put("dept_ids", userMap.get("dept_ids"));
                            map.put("dept_names", userMap.get("dept_names"));
                        }
                    }
                }
            }
        }

        return page;
    }


    /**
     * 递归查询子部门ID(包含自身)
     *
     * @param allDeptList
     * @param deptId
     * @param subDeptIds
     * @return
     */
    private List<String> recursionSubDeptIdsBySelf(List<SysDepart> allDeptList, String deptId, List<String> subDeptIds) {
        recursionSubDeptIds(allDeptList, deptId, subDeptIds);
        subDeptIds.add(deptId);
        return subDeptIds;
    }


    /**
     * 递归查询子部门ID
     *
     * @param allDeptList
     * @param deptId
     * @param subDeptIds
     * @return
     */
    private List<String> recursionSubDeptIds(List<SysDepart> allDeptList, String deptId, List<String> subDeptIds) {
        if (subDeptIds == null) {
            subDeptIds = new ArrayList<>();
        }
        for (SysDepart sysDepart : allDeptList) {
            if (deptId.equalsIgnoreCase(sysDepart.getParentId())) {
                subDeptIds.add(sysDepart.getId());
                recursionSubDeptIds(allDeptList, sysDepart.getId(), subDeptIds);
            }
        }
        return subDeptIds;
    }


    /**
     * 用户和客户信息转为map
     *
     * @param list
     * @return
     */
    private Map<String, Map<String, Object>> getUserCustomerInfoMap(List<Map<String, Object>> list) {
        Map<String, Map<String, Object>> map = new HashMap<>(16);
        if (list != null && list.size() > 0) {
            for (Map<String, Object> result : list) {
                String userId = result.get("user_id") == null ? "" : String.valueOf(result.get("user_id"));
                if (StringUtils.isNotBlank(userId)) {
                    map.put(userId, result);
                }
            }
        }
        return map;
    }

    /**
     * 添加用户
     *
     * @param sysUser
     * @param roleIds
     * @param departIds
     */
    @Transactional(rollbackFor = Exception.class)
    @Caching(
            evict = {
                    @CacheEvict(value = "drainage-auth-101", key = "'auth:checkPermissionsByperms:' + #sysUser.getId()"),
                    @CacheEvict(value = "drainage-auth-101", key = "'auth:getAllSysUserInfoList'")
            }
    )
    public void addUser(SysUser sysUser, String roleIds, String departIds) {
        try {
            this.save(sysUser);
            if (StringUtils.isNotEmpty(roleIds)) {
                String[] roleIdArray = roleIds.split(",");
                for (String roleId : roleIdArray) {
                    SysUserRole sysUserRole = new SysUserRole(sysUser.getId(), roleId);
                    sysUserRoleMapper.insert(sysUserRole);
                }
            }
            if (StringUtils.isNotEmpty(departIds)) {
                String[] departIdArray = departIds.split(",");
                for (String departId : departIdArray) {
                    SysUserDepart sysUserDepart = new SysUserDepart(sysUser.getId(), departId);
                    sysUserDepartMapper.insert(sysUserDepart);
                }
            }
        } catch (Exception e) {
            throw new BusinessException("添加用户失败");
        }
    }

    /**
     * 修改用户
     *
     * @param sysUser
     * @param roleIds
     * @param departIds
     */
    @Transactional(rollbackFor = Exception.class)
    @Caching(
            evict = {
                    @CacheEvict(value = "drainage-auth-101", key = "'auth:checkPermissionsByperms:' + #sysUser.getId()"),
                    @CacheEvict(value = "drainage-auth-101", key = "'auth:getAllSysUserInfoList'")
            }
    )
    public void editUser(SysUser sysUser, String roleIds, String departIds) {
        try {
            this.updateById(sysUser);
            sysUserRoleMapper
                    .delete(new QueryWrapper<SysUserRole>().lambda().eq(SysUserRole::getUserId, sysUser.getId()));
            if (StringUtils.isNotEmpty(roleIds)) {
                String[] roleIdArray = roleIds.split(",");
                for (String roleId : roleIdArray) {
                    SysUserRole sysUserRole = new SysUserRole(sysUser.getId(), roleId);
                    sysUserRoleMapper.insert(sysUserRole);
                }
            }
            sysUserDepartMapper
                    .delete(new QueryWrapper<SysUserDepart>().lambda().eq(SysUserDepart::getUserId, sysUser.getId()));
            if (StringUtils.isNotEmpty(departIds)) {
                String[] departIdArray = departIds.split(",");
                for (String departId : departIdArray) {
                    SysUserDepart sysUserDepart = new SysUserDepart(sysUser.getId(), departId);
                    sysUserDepartMapper.insert(sysUserDepart);
                }
            }
        } catch (Exception e) {
            throw new BusinessException("修改用户失败");
        }
    }

    /**
     * 批量删除用户
     *
     * @param ids
     */
    @Transactional(rollbackFor = Exception.class)
    @Caching(
            evict = {
                    @CacheEvict(value = "drainage-auth-101", key = "'auth:checkPermissionsByperms'", allEntries = true),
                    @CacheEvict(value = "drainage-auth-101", key = "'auth:getAllSysUserInfoList'", allEntries = true)
            }
    )
    public void deleteBatch(String ids) {
        try {
            LambdaQueryWrapper<SysUserRole> querySysUserRole = new LambdaQueryWrapper<SysUserRole>();
            LambdaQueryWrapper<SysUserDepart> querySysUserDepart = new LambdaQueryWrapper<SysUserDepart>();
            List<SysUser> list = new ArrayList<SysUser>();
            String[] array = ids.split(",");
            for (String id : array) {
                SysUser sysUser = new SysUser();
                sysUser.setId(id);
                sysUser.setDelFlag("1");
                list.add(sysUser);
                querySysUserRole.eq(SysUserRole::getUserId, id);
                querySysUserDepart.eq(SysUserDepart::getUserId, id);
                this.sysUserRoleMapper.delete(querySysUserRole);
                this.sysUserDepartMapper.delete(querySysUserDepart);
            }
            if (list.size() > 0) {
                this.updateBatchById(list);
            }
        } catch (Exception e) {
            throw new BusinessException("批量删除用户失败");
        }
    }

    public List<SysPermissionTree> getSysPermissionTreeByUserId(String userId, String platformCode) {
        try {
            List<SysPermission> list =
                    new ArrayList<SysPermission>(sysPermissionMapper.getSysPermissionByUserId(userId, platformCode));
            List<SysPermissionTree> treeList = new ArrayList<SysPermissionTree>();
            Collections.sort(list, new SysPermissionComparator());
            getTreeList(treeList, list, null);
            return treeList;
        } catch (Exception e) {
            throw new BusinessException("获取用户菜单列表失败");
        }
    }

    private void getTreeList(List<SysPermissionTree> treeList, List<SysPermission> metaList, SysPermissionTree temp) {
        for (SysPermission permission : metaList) {
            String tempPid = permission.getParentId();
            SysPermissionTree tree = new SysPermissionTree(permission);
            if (temp == null && StringUtils.isBlank(tempPid)) {
                treeList.add(tree);
                if (!tree.isLeaf()) {
                    getTreeList(treeList, metaList, tree);
                }
            } else if (temp != null && tempPid != null && tempPid.equals(temp.getId())) {
                temp.getChildren().add(tree);
                if (!tree.isLeaf()) {
                    getTreeList(treeList, metaList, tree);
                }
            }
        }
    }

    /**
     * 校验菜单权限编码
     *
     * @param perms
     * @param userId
     * @return
     */
    @Cacheable(value = "zk-auth-101", key = "'auth:checkPermissionsByperms:' + #userId + ':' + #perms", unless = "#result == false ")
    public boolean checkPermissionsByperms(String perms, String userId) {
        try {
            if (sysPermissionMapper.checkPermissionsExistsByPerms(perms) > 0) {
                int count = sysPermissionMapper.checkPermissionsByPerms(perms, userId);
                return count > 0;
            } else {
                return true;
            }
        } catch (Exception e) {
            throw new BusinessException("校验菜单权限编码失败");
        }
    }

    /**
     * 根据用户id列表查询用户列表
     *
     * @param idList
     * @return
     */
    public List<SysUser> getSysUserListByIdList(List<String> idList) {

        return this.listByIds(idList);
    }

    /**
     * 根据部门id和用户名称查询用户分页列表
     *
     * @param page
     * @param depId
     * @param username
     * @return
     */
    public IPage<SysUser> getDepartUserPage(Page<SysUser> page, String depId, String username) {
        IPage<SysUser> pageList = getMapper().getUserByDepId(page, depId, username);
        for (SysUser sysUser : pageList.getRecords()) {
            sysUser.setPassword("");
            sysUser.setSalt("");
        }
        return pageList;
    }

    /**
     * 根据角色id和用户名称查询用户分页列表
     *
     * @param page
     * @param roleId
     * @param username
     * @return
     */
    public IPage<SysUser> getRoleUserPage(Page<SysUser> page, String roleId, String username) {
        IPage<SysUser> pageList = getMapper().getUserByRoleId(page, roleId, username);
        for (SysUser sysUser : pageList.getRecords()) {
            sysUser.setPassword("");
            sysUser.setSalt("");
        }
        return pageList;
    }

    /**
     * 根据条件查询用户分页列表
     *
     * @return
     */
    public IPage<Map<String, Object>> getStaffUserPage(Req101121 req101121, String userId) {
        LambdaQueryWrapper<SysUser> qw = new LambdaQueryWrapper<SysUser>();
        qw.eq(SysUser::getParentId, userId);
        if (StringUtils.isNotEmpty(req101121.getKeyWord())) {
            qw.and(wrapper -> wrapper.like(SysUser::getUsername, req101121.getKeyWord()).or().like(SysUser::getRealname, req101121.getKeyWord()).or().like(SysUser::getPhone, req101121.getKeyWord()));
        }
        if (req101121.getStartTime() != null && req101121.getEndTime() != null) {
            qw.apply("DATE_FORMAT(create_time,'%Y-%m-%d') >= {0}", DateUtils.parseDateToDateStr(req101121.getStartTime()));
            qw.apply("DATE_FORMAT(create_time,'%Y-%m-%d') <= {0}", DateUtils.parseDateToDateStr(req101121.getEndTime()));
        }
        qw.eq(SysUser::getDelFlag, CommonConstant.DELETE_NO);
        qw.orderByDesc(SysUser::getCreateTime);
        return getMapper().selectSysUserPage(new Page<SysUser>(req101121.getCurrent(), req101121.getSize()), qw);
    }

    /**
     * 根据角色code查询 用户信息
     *
     * @param roleCode
     * @return
     */
    public List<SysUserRes> findAllUserByRoleCode(String roleCode) {
        if (StringUtil.isEmpty(roleCode)) {
            return new ArrayList<>();
        }
        List<SysUser> list = this.getMapper().getUserByRoleCode(roleCode);
        return CopyListUtils.copyList(list, SysUserRes.class);
    }

    /**
     * 根据用户id获取角色编码
     *
     * @param userId
     * @return
     */
    public String findRoleCodes(String userId) {
        if (null == userId) {
            return "";
        }
        List<SysRole> roleCodeByUserId = this.getMapper().getRoleCodeByUserId(userId);
        if (roleCodeByUserId == null || roleCodeByUserId.size() == 0) {
            return "";
        }
        return roleCodeByUserId.parallelStream().filter(sysRole -> StringUtil.isNotEmpty(sysRole.getRoleCode())).map(SysRole::getRoleCode).collect(Collectors.joining(","));
    }

    /**
     * 根据用户id判断是否超级管理员
     *
     * @param userId
     * @return
     */
    public boolean judgeIsSuperAdministrator(String userId) {
        List<String> list = this.getMapper().getRoleCodeByUserId(userId).stream().map(sysRole -> sysRole.getRoleCode()).collect(Collectors.toList());
        return list.contains(CommonConstant.ADMIN_ROLE_CODE);
    }

    /**
     * 查询所有用户列表
     *
     * @return
     */
    @Cacheable(value = "drainage-auth-101", key = "'auth:getAllSysUserInfoList'")
    public List<SysUserInfo> getAllSysUserInfoList() {

        return this.baseMapper.getAllSysUserInfoList();
    }
}
